/*
 * @Author: 晴鸢. 3013433857@qq.com
 * @Date: 2025-09-25 15:00:55
 * @LastEditors: 晴鸢. 3013433857@qq.com
 * @LastEditTime: 2025-09-27 10:17:37
 * @FilePath: /Learn/sem_cp/Ringqueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once
#include<iostream>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
const static int defaultcap=5;//缺省容量

template<class T>
class RingQueue
{
private:
    void P(sem_t&sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t&sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t&mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void unLock(pthread_mutex_t&mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
    
public:
    RingQueue(int cap=defaultcap)
        :_cap(cap)
        ,_cstep(0)
        ,_pstep(0)  
    {
        _ringqueue.resize(cap);
        sem_init(&cdata_sem,0,0); //消费者一开始可以消费的信号量为0
        sem_init(&pspace_sem,0,cap);//生产者可以生产的信号量为cap
        pthread_mutex_init(&c_mutex,nullptr);
        pthread_mutex_init(&p_mutex,nullptr);
    }
    //生产行为
    void Push(const T&in)
    {
        //PV操作在加锁之前是因为P操作本身是原子性的
        //而且在多线程中，还有利于并发进行PV操作
        P(pspace_sem);
        Lock(p_mutex);
        _ringqueue[_pstep]=in;
        //位置后移，维持环形特征
        _pstep++;
        _pstep%=_cap;
        unLock(p_mutex);
        V(cdata_sem);
    }
    //消费行为
    void Pop(T*out)
    {
        //PV操作在加锁之前是因为P操作本身是原子性的
        //而且在多线程中，还有利于并发进行PV操作
        P(cdata_sem);
        //将可以消费的数据带出
        Lock(c_mutex);
        *out=_ringqueue[_cstep];
        //位置后移，维持环形特征
        _cstep++;
        _cstep%=_cap;
        unLock(c_mutex);
        V(pspace_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&cdata_sem);
        sem_destroy(&pspace_sem);

        pthread_mutex_destroy(&c_mutex);
        pthread_mutex_destroy(&p_mutex);
    }
private:
    std::vector<T> _ringqueue;
    int _cap; //环形数组的容量
    int _cstep;//消费者的下标
    int _pstep;//生产者的下标

    sem_t cdata_sem;//消费者关注的数据资源
    sem_t pspace_sem;//生产者关注的空间资源

    pthread_mutex_t c_mutex;
    pthread_mutex_t p_mutex;
};